/*  Copyright (c) 2012 William Rogers and James Boud

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

using System;
using System.Collections.Generic;
using SlimDX;
using SlimDX.Direct3D11;

namespace JBBRXG11
{
    public class GraphicsDeviceManager : IDisposable
    //Microsoft.Xna.Framework.Graphics.IGraphicsDeviceService, //Microsoft.Xna.Framework.IGraphicsDeviceManager
    {
        public static readonly int DefaultBackBufferHeight = 600;
        public static readonly int DefaultBackBufferWidth = 800;
        public static readonly Microsoft.Xna.Framework.Graphics.SurfaceFormat
                       DefaultSurfaceFormat = Microsoft.Xna.Framework.Graphics.SurfaceFormat.Color;
        public static readonly Microsoft.Xna.Framework.Graphics.DepthFormat
                       DefaultDepthStencilFormat = Microsoft.Xna.Framework.Graphics.DepthFormat.Depth24Stencil8;

        // Assuming a one to one to one relationship between game, device manager and device
        class game_registration
        {
            public Game game;
            public GraphicsDeviceManager device_manager;
            public GraphicsDevice device;
            public game_registration(Game g, GraphicsDeviceManager m, GraphicsDevice dev)
            {
                game = g;
                device_manager = m;
                device = dev;
            }
        }
        static List<game_registration> game_register;  // Match game to device manager
        game_registration my_registration;

        Game the_game;

        public static readonly Microsoft.Xna.Framework.Graphics.SurfaceFormat[] ValidAdapterFormats  //???????
               = new Microsoft.Xna.Framework.Graphics.SurfaceFormat[] {
                                           Microsoft.Xna.Framework.Graphics.SurfaceFormat.Color
                                           };
        public static readonly Microsoft.Xna.Framework.Graphics.SurfaceFormat[] ValidBackBufferFormats
               = new Microsoft.Xna.Framework.Graphics.SurfaceFormat[] {
                                           Microsoft.Xna.Framework.Graphics.SurfaceFormat.Color,
                                           
                                           };
        public static readonly Microsoft.Xna.Framework.Graphics.DepthFormat[] ValidBackDepthBufferFormats
                = new Microsoft.Xna.Framework.Graphics.DepthFormat[] { Microsoft.Xna.Framework.Graphics.DepthFormat.Depth24Stencil8 };

        int preferredheight, preferredwidth;
        bool iswindowed;
        Microsoft.Xna.Framework.Graphics.SurfaceFormat preferredbackbufferformat;
        Microsoft.Xna.Framework.Graphics.DepthFormat preferreddepthstencilformat;
        public int PreferredBackBufferHeight { get { return preferredheight; } set { preferredheight = value; } }
        public int PreferredBackBufferWidth { get { return preferredwidth; } set { preferredwidth = value; } }
        public bool IsFullScreen { get { return !iswindowed; } set { iswindowed = !value; } }
        public Microsoft.Xna.Framework.Graphics.SurfaceFormat PreferredBackBufferFormat
        { get { return preferredbackbufferformat; } set { preferredbackbufferformat = value; } }
        public Microsoft.Xna.Framework.Graphics.DepthFormat PreferredDepthStencilFormat
        { get { return preferreddepthstencilformat; } set { preferreddepthstencilformat = value; } }

        static GraphicsDeviceManager()
        {
            game_register = new List<game_registration>();
        }

        internal static GraphicsDeviceManager GetGameManager(Game g)
        {
            foreach (game_registration reg in game_register)
            {
                if (reg.game == g) return reg.device_manager;
            }
            throw new Exception("Game has not registered a GraphicsDeviceManager");
        }

        internal static Game GetGame(GraphicsDevice dev)
        {
            foreach (game_registration reg in game_register)
            {
                if (reg.device == dev) return reg.game;
            }
            throw new Exception("GraphicsDevice is not associated with a Game");
        }

        public GraphicsDevice GraphicsDevice
        {
            get { return my_registration.device; }
        }

        public GraphicsDeviceManager(Game game)
        {
            the_game = game;
            my_registration = new game_registration(game, this, null);
            game_register.Add(my_registration);

            preferredheight = DefaultBackBufferHeight;
            preferredwidth = DefaultBackBufferWidth;
            iswindowed = true;
            preferreddepthstencilformat = DefaultDepthStencilFormat;
            preferredbackbufferformat = DefaultSurfaceFormat;
        }

        internal GraphicsDevice CreateDevice()
        {
            GraphicsDevice device = new GraphicsDevice(iswindowed, preferredwidth, preferredheight,
                                                       preferredbackbufferformat, preferreddepthstencilformat,
                                                       the_game.Window);
            // Note - device creation will cache whether or not the display is fullscreen and if so the screen size
            // in the game window object, so that it can return correct values for client area
            my_registration.device = device;

            return device;
        }


        #region stuff required

        ////
        //// Summary:
        ////     Specifies the set of valid device types supported by the GraphicsDeviceManager.
        //public static readonly DeviceType[] ValidDeviceTypes;

        ////
        //// Summary:
        ////     Gets or sets a value that indicates whether the device should start in full-screen
        ////     mode.
        //public bool IsFullScreen { get; set; }
        ////
        //// Summary:
        ////     Gets or sets the minimum pixel shader version required by the GraphicsDeviceManager.
        //public ShaderProfile MinimumPixelShaderProfile { get; set; }
        ////
        //// Summary:
        ////     Gets or sets the minimum vertex shader version required by the GraphicsDeviceManager.
        //public ShaderProfile MinimumVertexShaderProfile { get; set; }
        ////
        //public bool PreferMultiSampling { get; set; }

        ////
        //// Summary:
        ////     Gets or sets a value that indicates whether to sync to the vertical trace
        ////     (vsync) when presenting the back buffer.
        //public bool SynchronizeWithVerticalRetrace { get; set; }

        ////
        //// Summary:
        ////     Raised when the GraphicsDeviceManager is disposed.
        //public event EventHandler Disposed;
        ////
        //// Summary:
        ////     Raised when the GraphicsDeviceManager is changing the GraphicsDevice settings
        ////     (during reset or recreation of the GraphicsDevice). Reference page contains
        ////     code sample.
        ////
        //// Parameters:
        ////   :
        //public event EventHandler<PreparingDeviceSettingsEventArgs> PreparingDeviceSettings;

        //// Summary:
        ////     Applies any changes to device-related properties, changing the graphics device
        ////     as necessary.
        //public void ApplyChanges();
        ////
        //// Summary:
        ////     Determines whether the given GraphicsDeviceInformation is compatible with
        ////     the existing graphics device.
        ////
        //// Parameters:
        ////   newDeviceInfo:
        ////     Information describing the desired device configuration.
        //protected virtual bool CanResetDevice(GraphicsDeviceInformation newDeviceInfo);
        ////
        //// Summary:
        ////     Releases the unmanaged resources used by the GraphicsDeviceManager and optionally
        ////     releases the managed resources.
        ////
        //// Parameters:
        ////   disposing:
        ////     true to release both automatic and manual resources; false to release only
        ////     manual resources.
        //protected virtual void Dispose(bool disposing);
        ////
        //// Summary:
        ////     Finds the best device configuration that is compatible with the current device
        ////     preferences.
        ////
        //// Parameters:
        ////   anySuitableDevice:
        ////     true if the FindBestDevice can select devices from any available adapter;
        ////     false if only the current adapter should be considered.
        //protected virtual GraphicsDeviceInformation FindBestDevice(bool anySuitableDevice);
        ////
        //// Summary:
        ////     Called when a device is created. Raises the DeviceCreated event.
        ////
        //// Parameters:
        ////   sender:
        ////     The GraphicsDeviceManager.
        ////
        ////   args:
        ////     Arguments for the DeviceCreated event.
        //protected virtual void OnDeviceCreated(object sender, EventArgs args);
        ////
        //// Summary:
        ////     Called when a device is being disposed. Raises the DeviceDisposing event.
        ////
        //// Parameters:
        ////   sender:
        ////     The GraphicsDeviceManager.
        ////
        ////   args:
        ////     Arguments for the DeviceDisposing event.
        //protected virtual void OnDeviceDisposing(object sender, EventArgs args);
        ////
        //// Summary:
        ////     Called when the device has been reset. Raises the DeviceReset event.
        ////
        //// Parameters:
        ////   sender:
        ////     The GraphicsDeviceManager.
        ////
        ////   args:
        ////     Arguments for the DeviceReset event.
        //protected virtual void OnDeviceReset(object sender, EventArgs args);
        ////
        //// Summary:
        ////     Called when the device is about to be reset. Raises the DeviceResetting event.
        ////
        //// Parameters:
        ////   sender:
        ////     The GraphicsDeviceManager.
        ////
        ////   args:
        ////     Arguments for the DeviceResetting event.
        //protected virtual void OnDeviceResetting(object sender, EventArgs args);
        ////
        //// Summary:
        ////     Called when the GraphicsDeviceManager is changing the GraphicsDevice settings
        ////     (during reset or recreation of the GraphicsDevice). Raises the PreparingDeviceSettings
        ////     event.
        ////
        //// Parameters:
        ////   sender:
        ////     The GraphicsDeviceManager.
        ////
        ////   args:
        ////     The graphics device information to modify.
        //protected virtual void OnPreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs args);
        ////
        //// Summary:
        ////     Ranks the given list of devices that satisfy the given preferences.
        ////
        //// Parameters:
        ////   foundDevices:
        ////     The list of devices to rank.
        //protected virtual void RankDevices(List<GraphicsDeviceInformation> foundDevices);
        ////
        //// Summary:
        ////     Toggles between full screen and windowed mode.
        //public void ToggleFullScreen();
        #endregion

        public void Dispose()
        {
        }

        #region IGraphicsDeviceService Members

        public event EventHandler DeviceCreated;

        public event EventHandler DeviceDisposing;

        public event EventHandler DeviceReset;

        public event EventHandler DeviceResetting;

        #endregion

        #region IGraphicsDeviceManager Members

        //public bool BeginDraw()
        //{
        //    throw new NotImplementedException();
        //}

        //public void CreateDevice()
        //{
        //    throw new NotImplementedException();
        //}

        public void EndDraw()
        {
        }

        #endregion
    }
}
